package com.qingxin.sys.dao;

import java.io.Serializable;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import javax.annotation.Resource;

import org.hibernate.Criteria;
import org.hibernate.LockOptions;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.Restrictions;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.metadata.ClassMetadata;
import org.springframework.orm.hibernate4.SessionFactoryUtils;
import org.springframework.stereotype.Repository;
import org.springframework.util.Assert;

import com.qingxin.sys.entity.BaseEntity;
import com.qingxin.sys.mvc.Pager;
import com.qingxin.sys.utils.BeanUtil;



/**
 * Hibernate方式访问数据库的实现类
 * @author Administrator
 *
 * @param <T>
 * @param <ID>
 */
@Repository
public class HibernateDao<T extends BaseEntity,ID extends Serializable> implements IBaseDao<T,ID> {
	
	@Resource(name="sessionFactory")    
	protected SessionFactory sessionFactory;  
	
	protected Session getSession() {  
        return sessionFactory.getCurrentSession();  
    }  
	
	
	/**
	 * HIBERNATE 的 order 属性
	 */
	protected static final String ORDER_ENTRIES = "orderEntries";
	
	
	//保存一条记录到数据库
	@Override
	public T save(T entity) {
		 getSession().save(entity);
		 return entity;
	}

	
	//根据主键删除记录
	@Override
	public T delete(Class<T> clazz, ID id){
		T entity = this.get(clazz, id);
		if (entity != null) {
			getSession().delete(entity);
		}
		return entity;
    }
	
	
	//根据给定的实体删除对应的数据库记录
	@Override
	public T delete(T entity){
		getSession().delete(entity);
		return entity;
    }
	
	
	//更新指定记录
	@SuppressWarnings("unchecked")
	@Override
	public T update(Class<T> clazz, Updater<T> updater) {
		ClassMetadata metadata = sessionFactory.getClassMetadata(clazz);
		T oldEntity = (T) getSession().get(clazz, metadata.getIdentifier(updater.getEntity(), (SessionImplementor) getSession()));
		updaterCopyToPersistentObject(updater, oldEntity, metadata);
		return oldEntity;
	}
    
	
	/**
	 * 将更新对象拷贝至现有实体对象
	 * @param updater
	 * @param oldEntity
	 * @param metadata
	 */
	protected void updaterCopyToPersistentObject(Updater<T> updater, T oldEntity, ClassMetadata metadata) {
		String[] propNames = metadata.getPropertyNames();
		String identifierName = metadata.getIdentifierPropertyName();
		T entity = updater.getEntity();
		Object value = null;
		for(String propName : propNames) {
			if (propName.equals(identifierName)) {
				continue;
			}
			try {
				value = BeanUtil.getSimpleProperty(entity, propName);
				if (!updater.isUpdate(propName, value)) {
					continue;
				}
				metadata.setPropertyValue(oldEntity, propName, value);
			} catch (Exception e) {
				throw new RuntimeException("更新时设置字段值失败: '" + propName + "'", e);
			}
		}
	}
	
	
	//根据主键获取一个实体对象
	@Override
	public T get(Class<T> clazz, ID id) {
		return get(clazz, id, false);
	}

	
	//根据主键获取一个实体对象
	@SuppressWarnings("unchecked")
	@Override
	public T get(Class<T> clazz, ID id, boolean lock) {
		T entity = null;
		if (lock) {
			entity = (T) getSession().get(clazz, id, LockOptions.UPGRADE);
		} else {
			entity = (T) getSession().get(clazz, id);
		}
		return entity;
	}
	
	
	//从缓存中移除指定对象，可防止意外修改
	@Override
	public T evict(T entity){
		if(entity != null){
			getSession().evict(entity);
		}
		return entity;
	}

	
	//按属性获取指定对象，有多个时返回结果集中的第一条
	@SuppressWarnings("unchecked")
	@Override
	public T getByProperty(Class<T> clazz, String property, Object value) {
		Assert.hasText(property);
		Assert.notNull(value);
		Criteria criteria = getSession().createCriteria(clazz);
		criteria.add(Restrictions.eq(property, value));
		criteria.setMaxResults(1);//若有多条只取一个,避免报错
		return (T)criteria.uniqueResult();
	}

	
	//通过HQL查询数据列表
	@SuppressWarnings("rawtypes")
	@Override
	public List listByHql(String hql, Object... values) {
		return createQuery(hql, values).list();
	}
	
	
	//通过HQL查询指定对象，有多个时返回结果集中的第一条
	@Override
	public Object getByHql(String hql, Object... values) {
		Query query = createQuery(hql, values);
		query.setMaxResults(1);//若有多条只取一个,避免报错
		return query.uniqueResult();
	}
	
	
	//通过HQL更新数据库（更新/删除）
	@Override
	public int updateByHql(String hql, Object... values){
		return createQuery(hql, values).executeUpdate();
	}
	
	
	//通过Querier获得列表数据
	@SuppressWarnings("rawtypes")
	@Override
	public List listByQuerier(Querier querier) {
		Query query = createQuery(querier);
		List list = query.list();
		return list;
	}
	
	
	//通过Querier获得分页数据对象
	@SuppressWarnings("rawtypes")
	@Override
	public Pager pageByQuerier(Querier querier, int pageNo, int pageSize) {
		int totalCount = countResult(querier);
		Pager pager = new Pager(pageNo, pageSize, totalCount);
		if(totalCount < 1 || !pager.hasMoreData()) {
			pager.setList(new ArrayList());
			return pager;
		}
		
		Query query = getSession().createQuery(querier.getHql());
		setParamsToQuery(querier, query);
		query.setFirstResult(pager.getFirstResult());
		query.setMaxResults(pager.getPageSize());
		if (querier.isCacheable()) {
			query.setCacheable(true);
		}
		List list = query.list();
		pager.setList(list);
		return pager;
	}
	
	
	
	/**
	 * 根据HQL查询函数与参数列表创建Query对象,后续可进行更多处理,辅助函数
	 * @param queryString
	 * @param values
	 * @return
	 */
	protected Query createQuery(String queryString, Object... values) {
		Assert.hasText(queryString);
		Query queryObject = getSession().createQuery(queryString);
		if (values != null) {
			for (int i = 0; i < values.length; i++) {
				queryObject.setParameter(i, values[i]);
			}
		}
		return queryObject;
	}
	
	
	/**
	 * 根据Querier创建查询对象
	 * @param querier
	 * @return
	 */
	protected Query createQuery(Querier querier) {
		Session session = getSession();
		Query query = session.createQuery(querier.getHql());
		setParamsToQuery(querier, query);
		if (querier.getFirstResult() > 0) {
			query.setFirstResult(querier.getFirstResult());
		}
		if (querier.getMaxResults() > 0) {
			query.setMaxResults(querier.getMaxResults());
		}
		if (querier.isCacheable()) {
			query.setCacheable(true);
		}
		return query;
	}
	
	
	/**
	 * 获取记录总数
	 * @param querier
	 * @return
	 */
	protected int countResult(Querier querier) {
		Query query = getSession().createQuery(querier.getCountHql());
		setParamsToQuery(querier, query);
		if(querier.isCacheable()) {
			query.setCacheable(true);
		}
		java.util.Iterator<?> iter = query.iterate();
		if(iter.hasNext()){
			return ((Number) iter.next()).intValue();
		}else{
			return 0;
		}
	}
	
	
	/**
	 * 设置查询参数
	 * @param querier
	 * @param query
	 */
	protected void setParamsToQuery(Querier querier, Query query) {
		List<String> params = querier.getParams();
		if(params != null) {
			List<Object> values = querier.getValues();
			for(int i = 0, n = params.size(); i < n; i++) {
				query.setParameter(params.get(i), values.get(i));
			}
		}
		List<String> paramsList = querier.getParamsList();
		if(paramsList != null) {
			List<Collection<Object>> valuesList = querier.getValuesList();
			for(int i = 0, n = paramsList.size(); i < n; i++) {
				query.setParameterList(paramsList.get(i), valuesList.get(i));
			}
		}
		List<String> paramsArray = querier.getParamsArray();
		if(paramsArray != null) {
			List<Object[]> valuesArray = querier.getValuesArray();
			for (int i = 0, n = paramsArray.size(); i < n; i++) {
				query.setParameterList(paramsArray.get(i), valuesArray.get(i));
			}
		}
	}
	
	
	//获取JDBC连接，该数据库连接从c3p0连接池获取，使用完后需要调用其close方法关闭
	@Override
	public Connection getJdbcConnection() throws SQLException {
		return SessionFactoryUtils.getDataSource(sessionFactory).getConnection();
	}
	
}
